package org.xq.shop.maxaishop.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.RequestBody;
import org.xq.shop.maxaishop.conf.XqConstants;
import org.xq.shop.maxaishop.dao.*;
import org.xq.shop.maxaishop.entity.XqCommodity;
import org.xq.shop.maxaishop.entity.XqCorder;
import org.xq.shop.maxaishop.entity.XqCustomer;
import org.xq.shop.maxaishop.entity.XqRule;
import org.xq.shop.maxaishop.exception.EmptyStockException;
import org.xq.shop.maxaishop.service.XqCorderService;
import org.xq.shop.maxaishop.support.annotation.CacheParam;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * (XqCorder)表服务实现类
 *
 * @author makejava
 * @since 2021-06-17 19:44:30
 */
@Slf4j
@Service("xqCorderService")
public class XqCorderServiceImpl implements XqCorderService {
    @Resource
    private XqCorderDao xqCorderDao;
    @Resource
    private XqSpkieDao xqSpkieDao;
    @Resource
    private XqCommodityDao xqCommodityDao;
    @Resource
    private XqCustomerDao xqCustomerDao;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private XqRuleDao xqRuleDao;
    List<XqRule> xqRules = null;

    //订单处理多线程
    private ExecutorService threadPool = Executors.newFixedThreadPool(20);
//    private AtomicBoolean isRunning = new AtomicBoolean(false);
    private volatile boolean isStoped = false;
    //订单队列
    private volatile LinkedBlockingQueue<XqCorder> xqCordersQueue = new LinkedBlockingQueue<XqCorder>();

    @PostConstruct
    public void postConstruct() {
        xqRules = xqRuleDao.queryAll(null);
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                while(!isStoped) {
                    XqCorder xqCorder = null;
                    try {
                        xqCorder = xqCordersQueue.take();
                        if (xqCorder != null) {
                            insertSpikeOrder(xqCorder);
                        }
                    } catch (Exception e) {
                        if (!isStoped) {
                            log.error(e.getMessage(), e);
                            if (xqCorder != null) {
                                synchronized (xqCorder) {
                                    //Redis中缓存订单下单失败状态(-1), 用于在前端查看订单结果使用,缓存限时1个小时
                                    redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "-1", 3600, TimeUnit.SECONDS);
                                }
                            }
                        }
                    }
                }
            }
        });
    }

    @PreDestroy
    public void preDestory() {
        //停止线程
//        isRunning.set(false);
        isStoped = true;
        //关闭线程池
        if (threadPool != null) {
            threadPool.shutdown();
        }
    }

    public XqCorder insertSpikeOrder(XqCorder xqCorder) throws Exception {
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                transactionTemplate.execute(status -> {
                    try {
                        //减redis中的秒杀商品库存
                        Object stockObj =redisTemplate.opsForValue().get(XqConstants.MAXAISHOP_SPKIE_STORE + xqCorder.getSpkieId() + ":" + xqCorder.getCid());
                        Long leftStock = 0l;
                        //如果已售罄
                        if (stockObj != null && Long.parseLong(stockObj.toString()) > 0) {
                            leftStock = redisTemplate.opsForValue().decrement(XqConstants.MAXAISHOP_SPKIE_STORE + xqCorder.getSpkieId() + ":" + xqCorder.getCid());
                        } else {
                            String msg = String.format("商品已售罄，剩余库存%d", leftStock);
                            log.error(msg);
                            throw new EmptyStockException(msg);
                            //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                            //redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "-1", 30, TimeUnit.MINUTES);
                            //return Boolean.FALSE;
                        }
                        //减去秒杀商品库
                        int row = xqSpkieDao.updateSales(xqCorder.getSpkieId());
                        if (row == 0) { //如果减库存失败
                            //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                            //redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "-1", 30, TimeUnit.MINUTES);
                            //删除用户请求次数, 允许再下单
                            //redisTemplate.delete(XqConstants.MAXAISHOP_SPKIE_REPEAT_ORDER + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId());
                            //return Boolean.FALSE;
                            throw new Exception("减库存失败!");
                        }
                        //秒杀订单优惠序号
                        long num = redisTemplate.opsForValue().increment(XqConstants.MAXAISHOP_SPKIE_ORDER_NUM + xqCorder.getSpkieId());
                        //设置秒杀商品序号
                        xqCorder.setSpkieNum((int)num);
                        //获取打折规则，打折计算
                        for (XqRule xqRule : xqRules) {
                            if (xqRule != null & num <= xqRule.getRuleNumber()) {
                                double comOriginal = xqCorder.getCprice();//获取原价
                                double ruleRule = Double.parseDouble(xqRule.getRuleRule()); //转为折扣
                                //计算打折价格
                                double actual = comOriginal * ruleRule;
                                xqCorder.setCprice(actual); //赋值打折后的价格
                                break;
                            }
                        }
                        //如果是秒杀订单
                        xqCorder.setStatus(2);
                        int insert = 0;
                        //添加订单
                        insert = xqCorderDao.insert(xqCorder);
                        //记录下单状态, 2=已下单, 1=下单中, -1=下单失败, 缓存30分钟
                        redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "2", 30, TimeUnit.MINUTES);
                    } catch (DuplicateKeyException e) {
                        log.error("重复订单：{}", e.getMessage());
                        status.setRollbackOnly();
                        return Boolean.FALSE;
                    } catch (EmptyStockException e) {//库存售罄异常
                        log.error(e.getMessage());
                        status.setRollbackOnly();
                        if (xqCorder != null) {
                            //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                            redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "-1");
                        }
                        return Boolean.FALSE;
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        status.setRollbackOnly();
                        if (xqCorder != null) {
                            log.error("ID号{}的客户, 下单失败!", xqCorder.getCustomerId());
                            //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                            redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId(), "-1");
                            //删除用户请求次数, 允许再下单
                            redisTemplate.delete(XqConstants.MAXAISHOP_SPKIE_REPEAT_ORDER + xqCorder.getSpkieId() + ":" + xqCorder.getCustomerId());
                            //恢复redis减掉的库存
                            redisTemplate.opsForValue().increment(XqConstants.MAXAISHOP_SPKIE_STORE + xqCorder.getSpkieId() + ":" + xqCorder.getCid());
                        }
                    }
                    return Boolean.TRUE;
                });
            }
        }, xqCorder);
        return xqCorder;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param oid 主键
     * @return 实例对象
     */
    @Override
    public XqCorder queryById(Integer oid) {
        return this.xqCorderDao.queryById(oid);
    }

    @Override
    public List<XqCorder> selByCname(String cname, Integer start, Integer end) {
        return this.xqCorderDao.selByCname(cname, start, end);
    }

    @Override
    public List<XqCorder> selByUname(String uname, Integer start, Integer end) {
        return this.xqCorderDao.selByUname(uname, start, end);
    }


    /**
     * 查询下单结果方法
     *
     * @param xqCorder
     * @return
     */
    @Override
    public XqCorder getOrderResult(XqCorder xqCorder) {
        return xqCorderDao.getOrderResult(xqCorder);
    }

    @Override
    public int selCountMs(String cname) {
        return this.xqCorderDao.selCountMs(cname);
    }

    @Override
    public int selCount(String uname) {
        return this.xqCorderDao.selCount(uname);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<XqCorder> queryAllByLimit(int offset, int limit) {
        return this.xqCorderDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param xqCorder 实例对象
     * @return 实例对象
     */
    @Transactional //添加事务
    @Override
    public int insert(@RequestBody XqCorder xqCorder) {

        //获取产品对象
        XqCommodity xqCommodity = xqCommodityDao.queryById(xqCorder.getCid());
        //获取消费者对象
        XqCustomer xqCustomer = xqCustomerDao.queryById(xqCorder.getCustomerId());
        xqCorder.setCustomername(xqCustomer.getCustomerNickname());
        xqCorder.setCname(xqCommodity.getComName());
        //检查库存, 如果订单库存大于产品剩余库存, 直接返回
        if (xqCommodity.getComStork() < xqCorder.getCount()) {
            return 0;
        }
        xqCorder.setStatus(0);
        //减去普通商品库存
        xqCommodityDao.updateSales(xqCorder.getCount(), xqCorder.getCount(), xqCorder.getCid());
        return this.xqCorderDao.insert(xqCorder);
    }

    /**
     * 创建订单方法
     *
     * @param xqCorder 订单对象
     */
//    @CacheLock(prefix = "order_lock") //添加分布式锁
//    @Transactional //添加事务
    public boolean createOrder(@CacheParam(name = "xqCorder") @RequestBody XqCorder xqCorder) {
        //订单添加到队列
        xqCordersQueue.add(xqCorder);
        log.info("xqCordersQueue 队列：{} ", xqCordersQueue.size());
        return true;
        /*XqCorder xqCorder = null;
        try {
            xqCorder = xqCordersQueue.take();
            log.error("=================================doing");
            if (xqCorder != null) {
                //获取产品对象
                XqCommodity xqCommodity = xqCommodityDao.queryById(xqCorder.getCid());
                //获取消费者对象
                XqCustomer xqCustomer = xqCustomerDao.queryById(xqCorder.getCustomerId());
                xqCorder.setCustomername(xqCustomer.getCustomerNickname());
                xqCorder.setCname(xqCommodity.getComName());
                //如果是秒杀订单
                xqCorder.setStatus(2);

                //减去秒杀商品库
                int row = xqSpkieDao.updateSales(xqCorder.getSpkieId());
                if (row == 0) { //如果减库存失败
                    //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                    redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId()+ ":" + xqCorder.getCustomerId(), "-1");
                    //删除用户请求次数, 允许再下单
                    redisTemplate.delete(XqConstants.MAXAISHOP_SPKIE_REPEAT_ORDER + xqCorder.getSpkieId()+ ":" + xqCorder.getCustomerId());
                    return false;
                }
                long num = redisTemplate.opsForValue().increment(XqConstants.MAXAISHOP_SPKIE_ORDER_NUM + +xqCorder.getSpkieId());
                //设置秒杀商品序号
                xqCorder.setSpkieNum((int)num);
                if (xqRules != null) {
                //获取打折规则，打折计算
                for (XqRule xqRule : xqRules) {
                    if (xqRule !=null & num <= xqRule.getRuleNumber()) {
                        double comOriginal = xqCorder.getCprice();//获取原价
                        double ruleRule = Double.parseDouble(xqRule.getRuleRule()) ; //转为折扣
                        //计算打折价格
                        double actual = comOriginal * ruleRule;
                        xqCorder.setCprice(actual); //赋值打折后的价格
                        break;
                    }
                }}
                //添加订单
                int insert = xqCorderDao.insert(xqCorder);
                //记录下单状态, 2=已下单, 1=下单中, -1=下单失败, 缓存30分钟
                redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId()+ ":" + xqCorder.getCustomerId(), "2", 30, TimeUnit.MINUTES);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            if (xqCorder != null) {
                log.error("ID号{}的客户, 下单失败!", xqCorder.getCustomerId() );
                //记录下单状态, 2=已下单, 1=下单中, -1=下单失败
                redisTemplate.opsForValue().set(XqConstants.MAXAISHOP_SPKIE_ORDER_STATUS + xqCorder.getSpkieId()+ ":" + xqCorder.getCustomerId(), "-1");
                //删除用户请求次数, 允许再下单
                redisTemplate.delete(XqConstants.MAXAISHOP_SPKIE_REPEAT_ORDER + xqCorder.getSpkieId()+ ":" + xqCorder.getCustomerId());
            }
            return false;
        }*/
    }

    /**
     * 修改数据
     *
     * @param xqCorder 实例对象
     * @return 实例对象
     */
    @Override
    public XqCorder update(XqCorder xqCorder) {
        this.xqCorderDao.update(xqCorder);
        return this.queryById(xqCorder.getOid());
    }

    @Override
    public List<XqCorder> selectByUname(int uid) {
        return this.xqCorderDao.selectByUname(uid);
    }

    /**
     * 通过主键删除数据
     *
     * @param oid 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer oid) {
        return this.xqCorderDao.deleteById(oid) > 0;
    }

    @Override
    public int selectCount() {
        return this.xqCorderDao.selectCount();
    }

    @Override
    public List<XqCorder> selectAll(Integer start, Integer end) {
        return this.xqCorderDao.selectAll(start, end);
    }

    @Override
    public List<XqCorder> selectMs(Integer start, Integer end) {
        return this.xqCorderDao.selectMs(start, end);
    }

    @Override
    public int selectCountMs() {
        return this.xqCorderDao.selectCountMs();
    }

    @Override
    public int selectCountt(Integer uid) {
        return this.xqCorderDao.selectCountt(uid);
    }

    @Override
    public int updateStatus(String ornumber) {
        return this.xqCorderDao.updateStatus(ornumber);
    }

    @Override
    public XqCorder selectByOrnumber(String ornumber) {
        return this.xqCorderDao.selectByOrnumber(ornumber);
    }

    @Override
    public int insetPt(double cprice, int cid, int count, String ornumber, int customerId, String person, String address, String tel) {
      XqCorder xqCorder = new XqCorder();
        //获取产品对象
        XqCommodity xqCommodity = xqCommodityDao.queryById(cid);
        //获取消费者对象
        XqCustomer xqCustomer = xqCustomerDao.queryById(customerId);
        xqCorder.setCustomername(xqCustomer.getCustomerNickname());
        xqCorder.setCname(xqCommodity.getComName());
        xqCorder.setCount(count);
        xqCorder.setCprice(cprice);
        xqCorder.setOrnumber(ornumber);
        xqCorder.setPerson(person);
        xqCorder.setAddress(address);
        xqCorder.setTel(tel);
        xqCorder.setCid(cid);
        xqCorder.setCustomerId(customerId);
        //检查库存, 如果订单库存大于产品剩余库存, 直接返回
        if (xqCommodity.getComStork() < count) {
            return 0;
        }
        xqCorder.setStatus(3);
        //减去普通商品库存
        xqCommodityDao.updateSales(count,count, cid);
        return this.xqCorderDao.insert(xqCorder);
    }
}
